<?php
/**
 * Each engineer has a duty to keep the code elegant
 * Created by wolffy.
 * Author @wolffy<13750088090@sina.cn>
 * Date: 2018/8/14
 * Time: 23:18
 */
namespace App\Services\Xinyan;

class CertificationBankCardMsgAuth
{
    protected $idcardAuthUrl;//身份证认证信息
    protected $bankCardAuthUrl;//银行卡认证(三要素、四要素)
    protected $authApplyUrl;//银行卡四要素验证短信申请
    protected $authConfirmUrl;//银行卡四要素验证确认
    protected $bankCardBinUrl;//卡bin
    protected $mchid;//商户号
    protected $terminalid;//终端号
    protected $privatekeyPassword;//商户私钥密码
    protected $publicKey;//公钥
    protected $privatekey;//商户私钥

    private $transid;//商户订单号
    private $tradeDate;//交易时间
    private $tradeNo;//商户订单号
    private $idCard;//身份证号
    private $idHolder;//持卡人姓名
    private $isPhoto;//是否返回照片
    private $industryType;//根据自己的业务类型传入参数 A1 A6
    private $productType;//产品类型 0
    private $accNo;//银行卡号
    private $cardNo;//银行卡号
    private $mobile;//银行预留手机号
    private $smsCode;//短信验证码
    private $cardType;//卡类型
    private $validDateYear;//卡有效期年
    private $validDateMonth;//卡有效期月
    private $validNo;//cvv2码
    private $verifyElement;//验卡类型

    public function __construct()
    {
        $this->idcardAuthUrl = config('creditcard.idcard_auth_url');
        $this->bankCardAuthUrl = config('creditcard.bankcard_auth_url');
        $this->authApplyUrl = config('creditcard.auth_apply_url');
        $this->authConfirmUrl = config('creditcard.auth_confirm_url');
        $this->bankCardBinUrl = config('creditcard.bankcard_bin_url');
        $this->mchid = config('creditcard.mchid');
        $this->terminalid = config('creditcard.terminalid');
        $this->privatekeyPassword = config('creditcard.privatekey_password');
        $rsaPath = app_path() . '/Services/Xinyan/rsa/';
        $this->publicKey = $rsaPath . config('creditcard.rsa_publickey_name');
        $this->privatekey = $rsaPath . config('creditcard.rsa_privatekey_name');
    }

    /**
     * 请求参数
     * @return array
     */
    protected function requestParamsToJson()
    {
        $data = [
            "member_id" => $this->mchid,
            "terminal_id" => $this->terminalid,
            "trans_id" => $this->transid,
            "trade_date" => $this->tradeDate,
            "trade_no" => $this->tradeNo,
            "id_card" => $this->idCard,
            "id_holder" => $this->idHolder,
            "is_photo" => $this->isPhoto,
            "industry_type" => $this->industryType,
            "product_type" => $this->productType,
            "acc_no" => $this->accNo,
            "card_no"=> $this->cardNo,
            "mobile" => $this->mobile,
            "sms_code" => $this->smsCode,
            "card_type" => $this->cardType,
            "valid_date_year" => $this->validDateYear,
            "valid_date_month" => $this->validDateMonth,
            "valid_no" => $this->validNo,
            "verify_element" => $this->verifyElement,
        ];
        return str_replace("\\/", "/",json_encode($data));//转JSON
    }

    /**
     * 检查公钥文件是否存在
     * @return bool
     */
    public function isExistPublicKeyFile()
    {
        if (!file_exists($this->publicKey)) {
            return false;
        }
        return true;
    }

    /**
     * 检查私钥文件是否存在
     * @return bool
     */
    public function isExistPrivateKeyFile()
    {
        if (!file_exists($this->privatekey)) {
            return false;
        }
        return true;
    }

    /**
     * 获取接口请求结果
     * @param $dataContent
     * @return mixed
     */
    protected function getRequestResult($dataContent, $url)
    {
        $param = [
            "member_id" => $this->mchid,
            "terminal_id" => $this->terminalid,
            "data_type" => 'json',
            "data_content" => $dataContent
        ];
        //{"success":true,"data":{"code":"2","desc":"亲，认证信息不存在","trans_id":"07ade5b4-5fad-2bcf-08f2-f7c48b41998e","trade_no":"201808041442368253886579","fee":"N","photo":null},"errorCode":null,"errorMsg":null}
        $client = new \GuzzleHttp\Client(['verify' => false]);
        $response = $client->request('post', $url, ['form_params' => $param]);
        $json = json_decode($response->getBody()->getContents(), true);
        return $json;
    }

    /**
     * 身份证认证信息接口
     * @param $idCard
     * @param $idHolder
     * @param $isPhoto
     * @return mixed
     * array:4 [
     * "success" => true
     * "data" => array:6 [
     * "code" => "0"
     * "desc" => "亲，认证成功"
     * "trans_id" => "49669533-f9eb-34b6-0830-3f52b1237f3c"
     * "trade_no" => "201808142214420154205228"
     * "fee" => "Y"
     * "photo" => null
     * ]
     * "errorCode" => null
     * "errorMsg" => null
     * ]
     */
    public function identityIdCard($idCard, $idHolder, $isPhoto, $industryType)
    {
        $this->idCard = $idCard;
        $this->idHolder = $idHolder;
        $this->isPhoto = $isPhoto;
        $this->industryType = $industryType;
        $this->transid = $this->createUuid();//商户订单号
        $this->tradeDate = $this->tradeDate();//交易时间
        $dataContent = $this->requestParamsToJson();
        $dataContent = $this->encryptedByPrivateKey($dataContent);
        return $this->getRequestResult($dataContent, $this->idcardAuthUrl);
    }

    /**
     * 银行卡认证(三要素、四要素)
     * @param $idCard
     * @param $idHolder
     * @param $isPhoto
     * @return mixed
     * array:4 [
     * "success" => true
     * "data" => array:9 [
     * "code" => "0"
     * "desc" => "亲，认证成功"
     * "trans_id" => "475eab7e-215c-573d-334d-c32db6a556dd"
     * "trade_no" => "201808151042480714877284"
     * "org_code" => null
     * "org_desc" => null
     * "fee" => "Y"
     * "bank_id" => "ICBC"
     * "bank_description" => "中国工商银行"
     * ]
     * "errorCode" => null
     * "errorMsg" => null
     * ]
     */
    public function identityBankCardThreeFourPoint($accNo, $mobile, $verifyElement, $idCard,
                                                   $idHolder, $industryType, $productType)
    {
        $this->accNo = $accNo;
        $this->mobile = $mobile;
        $this->verifyElement = $verifyElement;

        $this->idCard = $idCard;
        $this->idHolder = $idHolder;
        $this->industryType = $industryType;
        $this->productType = $productType;

        $this->transid = $this->createUuid();//商户订单号
        $this->tradeDate = $this->tradeDate();//交易时间
        $dataContent = $this->requestParamsToJson();
        // **** 先BASE64进行编码再RSA加密 ***
        $dataContent = $this->encryptedByPrivateKey($dataContent);
        return $this->getRequestResult($dataContent, $this->bankCardAuthUrl);
    }

    /**
     * 银行卡四要素验证短信申请
     */
    public function identityBankCardFourPointSmsApply($accNo, $mobile, $cardType, $idCard, $idHolder)
    {
        $this->accNo = $accNo;
        $this->mobile = $mobile;
        $this->cardType = $cardType;

        $this->idCard = $idCard;
        $this->idHolder = $idHolder;

        $this->transid = $this->createUuid();//商户订单号
        $this->tradeDate = $this->tradeDate();//交易时间
        $dataContent = $this->requestParamsToJson();
        // **** 先BASE64进行编码再RSA加密 ***
        $dataContent = $this->encryptedByPrivateKey($dataContent);
        return $this->getRequestResult($dataContent, $this->authApplyUrl);
    }

    /**
     * 银行卡四要素验证确认
     */
    public function identityBankCardFourPoint($smsCode)
    {
        $this->smsCode = $smsCode;

        $this->tradeNo = $this->createUuid();//商户订单号
        $dataContent = $this->requestParamsToJson();
        // **** 先BASE64进行编码再RSA加密 ***
        $dataContent = $this->encryptedByPrivateKey($dataContent);
        return $this->getRequestResult($dataContent, $this->authConfirmUrl);
    }

    /**
     * 卡宾
     */
    public function identityBankCardGuest($accNo, $industryType, $productType)
    {
        $this->cardNo = $accNo;

        $this->industryType = $industryType;
        $this->productType = $productType;

        $this->transid = $this->createUuid();//商户订单号
        $this->tradeDate = $this->tradeDate();//交易时间
        $dataContent = $this->requestParamsToJson();
        // **** 先BASE64进行编码再RSA加密 ***
        $dataContent = $this->encryptedByPrivateKey($dataContent);
        return $this->getRequestResult($dataContent, $this->bankCardBinUrl);
    }

    /**
     * 生成时间
     * 生成yyyymmddHHmiss 20160921142808
     * @return bool|string
     */
    protected function tradeDate()
    {
        return date('YmdHis',time());

    }

    /**
     * 生成唯一订单号
     * @param string $prefix
     * @return string
     */
    protected function createUuid($prefix = "")
    {
        //可以指定前缀
        $str = md5(uniqid(mt_rand(), true));
        $uuid  = substr($str,0,8) . '-';
        $uuid .= substr($str,8,4) . '-';
        $uuid .= substr($str,12,4) . '-';
        $uuid .= substr($str,16,4) . '-';
        $uuid .= substr($str,20,12);
        return $prefix . $uuid;
    }

    /**
     * 获取私钥
     * @return mixed
     */
    public function getPrivateKey()
    {
        ob_start();
        // 初始化商户私钥
        $pkcs12 = file_get_contents($this->privatekey);
        $privateKey = array();
        openssl_pkcs12_read($pkcs12, $privateKey, $this->privatekeyPassword);
        ob_end_clean();
        return $privateKey["pkey"];
    }

    /**
     * 获取公钥
     * @return resource
     */
    public function getPublicKey()
    {
        ob_start();
        //宝付公钥
        $keyFile = file_get_contents($this->publicKey);
        ob_end_clean();
        return openssl_get_publickey($keyFile);
    }

    /**
     * 私钥加密
     * @param $data_content
     * @return string
     */
    function encryptedByPrivateKey($requestParams)
    {
        $data = base64_encode($requestParams);
        $encrypted = "";
        $totalLen = strlen($data);
        $encryptPos = 0;
        while ($encryptPos < $totalLen) {
            openssl_private_encrypt(substr($data, $encryptPos, 117), $encryptData, $this->getPrivateKey());
            $encrypted .= bin2hex($encryptData);
            $encryptPos += 117;
        }
        return $encrypted;
    }

    /**
     * 公钥解密
     * @param $encrypted
     * @return bool|string
     * @throws \Exception
     */
    function decryptByPublicKey($encrypted)
    {
        if (!function_exists( 'hex2bin')) {
            throw new \Exception("请启用hex2bin方法");
        }
        $decrypt = "";
        $totalLen = strlen($encrypted);
        $decryptPos = 0;
        while ($decryptPos < $totalLen) {
            openssl_public_decrypt(hex2bin(substr($encrypted, $decryptPos, 256)), $decryptData, $this->getPublicKey());
            $decrypt .= $decryptData;
            $decryptPos += 256;
        }
        $decrypt = base64_decode($decrypt);
        return $decrypt;
    }
}